/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sync;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import sync.io.Repository;
import sync.model.Assignment;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import org.apache.http.conn.HttpHostConnectException;
import sync.model.Assignment.Status;
import sync.model.AssignmentItem;
import sync.model.Catalog;
import sync.model.UserInfo;
import sync.services.ChartReaderService;
import sync.services.SyncException;

/**
 * Manages the synchronization with the ChartReader server
 * @author yarden
 */
public class SyncManager {
    
    /* 
     * Connection information
     * TODO: These should be read from configuration files
     */
    public final String SERVICE_URL     = "localhost";
    public final int SERVICE_PORT       = 8080;
    
    // TODO: switch to secure communication channels
    private String username = "";
    private String password;
    private boolean authenticated;
    
    private AssignmentsScreen view;
    private Repository repository = null;
    private Catalog catalog = null;
    private ChartReaderService service;
    
    
    /**
     * Constructor. In order to decouple the view and the presenter the SyncManger is provided with the view to use
     * 
     * @param view to be used 
     */
    public SyncManager(AssignmentsScreen view) {
        this.view = view;
    }
    
    public void resetUser() {
        if (!username.equals("")) {
            username = "";
            view.setLastSync("");
            view.setAssignments( new ArrayList<AssignmentItem>(), new ArrayList<AssignmentItem>(), new ArrayList<AssignmentItem>());
            view.setStatus("");
        } 
    }
    
    public void setUsername(String username) {
        if (this.username != null && this.username.equals(username)) 
            return;
            
        this.username = username;
        password = null;
        authenticated = false;

        if (repository == null) repository = new Repository();
        if (catalog == null) catalog = new Catalog();
        
        catalog.readUserCatalog(username, repository.getCatalog());
        
        UserInfo info = catalog.getUserInfo();
        
        if (info.isNewUser())
            view.setStatus("New user");
        else 
            view.setLastSync(info.getLastSync());
        
        // show assignments 
        showAssignments(info.getAssignments());
    }
   
    
    public void sync() {
        if (service == null)
            service = new ChartReaderService(SERVICE_URL, SERVICE_PORT);
        try {
            UserInfo info = catalog.getUserInfo();
            // authenticate
            // TODO
            
            submitAssignments(info.getUsername());
           
            // fetch new assignments from the server
            List<Assignment> list = service.getAssignments(username);
            
            // check with assignments are new
            List<Assignment> newAssignments = findNewAssignments(info.getAssignments(), list);
            
            // update list of asignments
            info.getAssignments().addAll(newAssignments); 
            
            // fetch actual assignments from the server
            fetchNewAssignments(newAssignments);
            
            // update the screen
            showAssignments(info.getAssignments());
            
            // cleanup
            DateFormat formater = new SimpleDateFormat();
            info.setLastSync(formater.format(Calendar.getInstance().getTime()));
            view.setLastSync(info.getLastSync());
            
            // update the local catalog
            catalog.updateCatalog(repository.getCatalog());
        } catch(SyncException e) {
            view.setStatus(e.getMessage());
        }
    }
    
    
    private void submitAssignments(String user) {
        // find which assignments to submit
        List<AssignmentItem> report = new ArrayList<AssignmentItem>();
        
        report.addAll(getUpdatedAssignments(Assignment.Status.InProgress));
        report.addAll(getUpdatedAssignments(Assignment.Status.Done));
        report.addAll(getUpdatedAssignments(Assignment.Status.OnHold));
        
        if (report.size() > 0)
            service.updateAssignments(user, report);
    }
    
    private List<AssignmentItem> getUpdatedAssignments(Assignment.Status status) {
        List<AssignmentItem> report = new ArrayList<AssignmentItem>();
        
        List<AssignmentItem> assignments = view.getAssignments(status);
        
        for (AssignmentItem item : assignments ) {
            if (item.isDirty()) {
                report.add(item);
                if (item.getStatus() == Assignment.Status.Done && item.getServerStatus() != Assignment.Status.Done) 
                     item.setCompleted(Calendar.getInstance().getTime().toString());
                item.setServerStatus(status);
            }
        }
        
        return report;
    }
    
    
    private List<Assignment> findNewAssignments(List<Assignment> a, List<Assignment> b) {
        List<Assignment> list = new ArrayList<Assignment>();
        
        for (Iterator<Assignment> i = b.iterator(); i.hasNext(); ) {
            Assignment assignment = i.next();
            Assignment prev = findAssignment(a, assignment);
            if (prev == null) {
                list.add(assignment);
            }
        }
        return list;
    }
    
    
    private Assignment findAssignment(List<Assignment> list, Assignment assignment ) {
        for (Iterator<Assignment> i = list.iterator(); i.hasNext(); ) {
            Assignment a = i.next();
            if (a.getId().equals(assignment.getId()))
                return a;
        }
        return null;
    }
    
    private void showAssignments(List<Assignment> assignments) {
            
        List<AssignmentItem> inProgress = new ArrayList<AssignmentItem>();
        List<AssignmentItem> onHold = new ArrayList<AssignmentItem>();
        List<AssignmentItem> done = new ArrayList<AssignmentItem>();
        
        for (Iterator<Assignment> a = assignments.iterator(); a.hasNext(); ) {
            Assignment assignment = a.next();
            for (Iterator<AssignmentItem> i = assignment.getItems().iterator(); i.hasNext(); ) {
                AssignmentItem item = i.next();
                if (item.getStatus() == Status.InProgress) {
                    inProgress.add(item);
                } else if (item.getStatus() == Status.OnHold) {
                    onHold.add(item);
                } else { 
                    done.add(item);
                }
            }
        }
        
        view.setAssignments( inProgress, done, onHold);
    }
    
    
    private void fetchNewAssignments(List<Assignment> list) throws SyncException {
        for (Iterator<Assignment> i = list.iterator(); i.hasNext(); ) {
            Assignment assignment = i.next();
            repository.createAssignment(assignment);
            
            // get schema
//            String schema = service.getSchema(assignment.getSchemaId());
//            repository.saveSchema(assignment, schema);
            
            // get texts
            for (Iterator<AssignmentItem> j = assignment.getItems().iterator(); j.hasNext(); ) {
                AssignmentItem item = j.next();
                String text = service.getAssignmentItem(item);
                repository.saveAssignmentItem(item, text);
            }
        }
    }
    
}
